﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;

namespace InterLinq.Client {
	/// <summary>
	/// Abstract implementation of an <see cref="IQueryHandler"/>.
	/// This class provides methods to get an <see cref="IQueryable{T}"/>.
	/// </summary>
	/// <seealso cref="IQueryHandler"/>
	public class InterLinqQueryHandler : IQueryHandler {
		#region Fields

		/// <summary>
		/// Gets the <see cref="IQueryProvider"/>.
		/// </summary>
		public InterLinqQueryProvider QueryProvider { get; private set; }

		#endregion

		#region Constructors

		/// <summary>
		/// Empty constructor.
		/// </summary>
		public InterLinqQueryHandler(InterLinqQueryProvider provider) {
			QueryProvider = provider;
		}

		#endregion

		private readonly List<Type> m_Types = new List<Type>();

		#region IQueryHandler Members

		public ReaderWriterLock LockOfDataSource {
			get { throw new NotImplementedException(); }
		}

		public IEnumerable<Type> GetTableTypes() {
			return m_Types;
		}

		/// <summary>
		/// Returns an <see cref="IQueryable{T}"/>.
		/// </summary>
		/// <typeparam name="T">Type of the returned <see cref="IQueryable{T}"/>.</typeparam>
		/// <returns>Returns an <see cref="IQueryable{T}"/>.</returns>
		/// <seealso cref="IQueryHandler.GetTable"/>
		public virtual IQueryable<T> GetTable<T>() where T : class {
			if (!m_Types.Contains(typeof(T))) {
				m_Types.Add(typeof(T));
			}
			return new InterLinqQuery<T>(QueryProvider);
		}

		/// <summary>
		/// Returns an <see cref="IQueryable"/>.
		/// </summary>
		/// <param name="type">Type contained in the returned <see cref="IQueryable"/>.</param>
		/// <returns>Returns an <see cref="IQueryable"/>.</returns>
		/// <seealso cref="IQueryHandler.GetTable{T}"/>
		public virtual IQueryable GetTable(Type type) {
			if (!m_Types.Contains(type)) {
				m_Types.Add(type);
			}
			MethodInfo getTableMethod = GetType().GetMethod("GetTable", new Type[] { });
			MethodInfo genericGetTableMethod = getTableMethod.MakeGenericMethod(type);
			return (IQueryable)genericGetTableMethod.Invoke(this, new object[] { });
		}

		/// <summary>
		/// Tells the <see cref="IQueryHandler"/> to start a new the session.
		/// </summary>
		/// <returns>True, if the session creation was successful. False, if not.</returns>
		/// <seealso cref="IQueryHandler.StartSession"/>
		public virtual bool StartSession() {
			return true;
		}

		/// <summary>
		/// Tells the <see cref="IQueryHandler"/> to close the current session.
		/// </summary>
		/// <returns>True, if the session closing was successful. False, if not.</returns>
		/// <seealso cref="IQueryHandler.CloseSession"/>
		public virtual bool CloseSession() {
			return true;
		}

		#endregion
	}
}